package org.shangrila.app.wfm.mb;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import javax.inject.Inject;
import javax.inject.Named;

import org.primefaces.event.FileUploadEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.event.UnselectEvent;
import org.primefaces.model.diagram.DefaultDiagramModel;
import org.shangrila.app.sys.cfg.AppInitInfo;
import org.shangrila.app.sys.shiro.SecUtil;
import org.shangrila.app.wechat.bean.WechatMessageUtils;
import org.shangrila.app.wechat.utils.WeChatUtil;
import org.shangrila.bme.eo.AppFileInfo;
import org.shangrila.bme.eo.BmeAcception;
import org.shangrila.bme.eo.BmeContract;
import org.shangrila.bme.eo.BmePurchOrder;
import org.shangrila.bme.eo.BmeReceipt;
import org.shangrila.comm.dao.DbAccess;
import org.shangrila.comm.helper.IDHelper;
import org.shangrila.comm.helper.JsonHelper;
import org.shangrila.comm.helper.StringHelper;
import org.shangrila.comm.utils.FileUtil;
import org.shangrila.wfm.core.WfmEngine;
import org.shangrila.wfm.core.WfmHelper;
import org.shangrila.wfm.eo.WfmNode;
import org.shangrila.wfm.eo.WfmTask;
import org.shangrila.wfm.eo.WfmTaskLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Named
@SessionScoped
public class WfmTaskMgrMB implements Serializable{
	private static final Logger log = LoggerFactory.getLogger(WfmTaskMgrMB.class);
	private static final long serialVersionUID = 4799456092581896951L;
	private static final String UI_TAST_TODO="ui-task-todo";

	private String uiTaskTodoPage=UI_TAST_TODO;  //任务完成页面视图
	private String operator;  
	private String serviceNo;  
	private List<WfmTask> voList= new ArrayList<WfmTask>() ; 
	private List<WfmTaskLog> voListLog=new ArrayList<WfmTaskLog>() ;  
	private WfmEngine engine = null;	
	private WfmTask selectedTask;
	private DefaultDiagramModel model;
	private int workResult;
	private String workRemarks;
	private String rollbackNode;
	private List<SelectItem> nodeList=new ArrayList<SelectItem>();

	private String uploadedFile="";
	
	private String weixin_inform_userids="";
	private String weixin_inform_text="";
	
	@Inject
	private DbAccess db;

	/**  
	 * <p>Title: findCurrentNode</p>  
	 * <p>Description: 通过当前任务名、当前流程获取当前节点</p>  
	 * @param taskName
	 * @param process
	 * @return  
	 */
	public WfmNode findCurrentNode(WfmTask task) {
		
		StringBuilder nodeSql = 
				new StringBuilder("select m from WfmNode m ");
		StringBuilder nodeWhere=new StringBuilder("where m.name=?1 and m.wfmProcess=?2");
		List<Object> params=new ArrayList<>();
		params.add(0,task.getTaskName());
		params.add(1,task.getWfmProcess());
		nodeSql.append(nodeWhere.toString()); 
		db.begin();
		List<WfmNode> curtNodes = db.findBySql(nodeSql.toString(), params.toArray());
		db.commit();
		WfmNode curtNode = curtNodes.get(0);
		return curtNode;
	}
	
	/**  
	 * <p>Title: findNextNode</p>  
	 * <p>Description: 根据当前节点、当前节点流程获取下一个节点</p>  
	 * @param currentNode
	 * @param process
	 * @return  
	 */
	public WfmNode findNextNode(WfmTask task) {
		
		WfmNode currentNode = findCurrentNode(task);
		int seqno = Integer.parseInt(currentNode.getSeqno());
		seqno=seqno+1;
		StringBuilder nodeSql=new StringBuilder("select m from WfmNode m ");
		StringBuilder nodeWhere=new StringBuilder("where m.wfmProcess=?1 and m.seqno=?2");
		List<Object> params=new ArrayList<>();
		params.clear();
		params.add(0,task.getWfmProcess());
		params.add(1,String.valueOf(seqno));
		nodeSql.append(nodeWhere.toString());
		db.begin();
		List<WfmNode> nextNodes = db.findBySql(nodeSql.toString(),params.toArray());
		WfmNode nextNode = nextNodes.get(0);
		db.commit();
		return nextNode;
	}
	
	/**  
	 * <p>Title: getRoleByNode</p>  
	 * <p>Description: 获得当前节点角色的用户的微信公众号</p>  
	 * @param node
	 * @return  
	 */
	public String getUsersByNode(WfmNode node) {
		
		String assignee=null;
		List<Object> params=new ArrayList<>();
		
		if("task".equals(node.getNodeType())) {
			assignee=node.getAssignee();
		}
		params.add(0, assignee);
		
		StringBuilder roleSql=
				new StringBuilder("SELECT u.wxno FROM sys_users u " + 
				"LEFT JOIN sys_role_user ru ON u.ID=ru.USERID " + 
				"LEFT JOIN sys_roles r ON ru.ROLEID=r.ID ");
		StringBuilder roleWhere=
				new StringBuilder("WHERE r.ID=(SELECT r.ID FROM sys_roles r WHERE r.`NAME`=?1)");
		roleSql.append(roleWhere.toString());
		db.begin();
		List<Object[]> roleUsers = db.findEntityByNSql(roleSql.toString(), params.toArray(), true);
		db.commit();
		StringBuilder roleList=new StringBuilder();
		for (Object sysUser : roleUsers) {
			if(roleList.length()==0) {
				roleList.append(sysUser.toString());
			}else {
				roleList.append("|"+sysUser.toString());
			}
		}
		return roleList.toString();
	}
	
	/**  
	 * <p>Title: getEnityByTask</p>  
	 * <p>Description: 根据当前任务获取不同的实体类</p>  
	 * @param task
	 * @return  
	 */
	public Map<String,Object> getEnityByTask(WfmTask task) {
		
		String processName = task.getProcessName();
		Map<String,Object> map=new HashMap<>();
		if("wf_cgdd".equals(processName)) {
			BmePurchOrder purchOrder = new BmePurchOrder();
			db.begin();
			purchOrder=db.findById(purchOrder.getClass(), task.getServiceNo());
			map.put(processName, purchOrder);
			db.commit();
		}else if("wf_fhd".equals(processName)) {
			BmeReceipt receipt = new BmeReceipt();
			db.begin();
			receipt=db.findById(receipt.getClass(), task.getServiceNo());
			map.put(processName, receipt);
			db.commit();
		}else if("wf_ysdsh".equals(processName)) {
			BmeAcception acception = new BmeAcception();
			db.begin();
			acception=db.findById(acception.getClass(), task.getServiceNo());
			map.put(processName, acception);
			db.commit();
		}else if("wf_htbgsq".equals(processName)) {
			BmeContract contract = new BmeContract();
			db.begin();
			contract=db.findById(contract.getClass(), task.getServiceNo());
			map.put(processName, contract);
			db.commit();
		}	
		
		return map;	
	}
	
	
	public void sendWxMessage(WfmTask task) {
		//获取下一个节点的
		WfmNode nextNode = findNextNode(task);
		//获取下一个节点的用户微信号
		String nodeUsersWx = getUsersByNode(nextNode);
		
		Map<String, Object> map = getEnityByTask(task);
		Iterator<Entry<String, Object>> iterator = map.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, Object> next = iterator.next();
			if("wf_cgdd".equals(next.getKey())) {
				BmePurchOrder purchOrder=(BmePurchOrder)next.getValue();
				WeChatUtil.sendTextMessage(nodeUsersWx, purchOrder.toString());
			}else if("wf_fhd".equals(next.getKey())) {
				BmeReceipt receipt=(BmeReceipt)next.getValue();
				WeChatUtil.sendTextMessage(nodeUsersWx, receipt.toString());
			}else if("wf_ysdsh".equals(next.getKey())) {
				BmeAcception acception=(BmeAcception)next.getValue();
				WeChatUtil.sendTextMessage(nodeUsersWx, acception.toString());
			}else if("wf_htbgsq".equals(next.getKey())) {
				BmeContract contract=(BmeContract)next.getValue();
				WeChatUtil.sendTextMessage(nodeUsersWx, contract.toString());
			}else if("wf_htsh".equals(next.getKey())) {
				//发送节点完成任务
				BmeContract contract=(BmeContract)next.getValue();
				WeChatUtil.sendTextMessage(nodeUsersWx, contract.toString());
				
				//下一个节点为end节点时，修改合同状态
				String name = nextNode.getName();
				if("end".equals(name)) {
					contract.setStatus("3");
					db.begin();
					db.update(contract);
					db.commit();
				}
			}
			
			break;
		}
		
	}
	
	
	public WfmTaskMgrMB() {
		engine = WfmHelper.getEngine();
		try{
			operator = SecUtil.getCachedShiroUser().getUserno();
		}
		catch(Exception ex){
			operator="wfm";
		}
		if(null!=selectedTask)
			serviceNo = selectedTask.getServiceNo();
		
		queryTaskList();
	}
	
	//根据当前用户查询流程实例列表
	public String queryTaskList() {
		if(StringHelper.isEmpty(serviceNo))
			voList = engine.getWfmdao().findTaskByOperatorOrRoles(operator, SecUtil.getCachedShiroRoles());
		else
			voList = engine.getWfmdao().findTaskByServiceNo(serviceNo);
		return null;
	}
	
	//根据当前用户查询流程实例列表(LOG)
	public String queryTaskLogList() {
		if(StringHelper.isEmpty(serviceNo))
			voListLog = engine.getWfmdao().findTaskLogAll();
		else
			voListLog = engine.getWfmdao().findTaskLogByServiceNo(serviceNo);
			
		return null;
	}

	public String commitTask() {
		selectedTask.setResult(workResult);
		selectedTask.setRemarks(rollbackNode+"|"+workRemarks);

		if(0 == workResult){
			//流向下一个环节就
			engine.commitTask(selectedTask, operator, genTaskArgs());
			
			//该环节处理完，通知下一个环节处理人
			WechatMessageUtils.sendWxMessageToNextNode(selectedTask,operator);
			showMessages("流程任务提交","处理成功。");
			
		}
		else if(1 == workResult){
			//任务环节回退
			engine.rollbackTask(selectedTask, operator, rollbackNode, genTaskArgs());
			//通知回退节点的处理人
			WechatMessageUtils.sendWxMessageToAnyNode(selectedTask, rollbackNode, operator);
			//通知流程发起人
			WechatMessageUtils.sendWxMessageToInitiators(selectedTask, operator, selectedTask.getServiceCreator());
			
		}
		
		//审核通过通知内务、项目经理
		if(WechatMessageUtils.JudgeState(selectedTask)) {
			WechatMessageUtils.sendMessageToInterPm(selectedTask);
		}
		

		//微信通知
		WeChatUtil.sendTextMessage(weixin_inform_userids,weixin_inform_text);
		
		
		//移出当前处理完成的任务
		voList.remove(selectedTask);
		if(!voList.isEmpty()) 
			selectedTask = voList.get(0);
		return null;
	}
	
	//处理流程逻辑,返回流程任务参数
	@SuppressWarnings("unchecked")
	public Map<String, Object> genTaskArgs() {
		//流程参数
		Map<String, Object> args = new HashMap<String, Object>();	
		args = JsonHelper.fromJson(selectedTask.getVariable(),Map.class);	//获取流程参数
		
		String processName = selectedTask.getProcessName();
		String taskName = selectedTask.getTaskName();
		String operatorNo="";	

		if(AppInitInfo.PROCESS_WF_CGDD.equals(processName)){ //订单流程		
			if("wf_cgdd_check".equals(taskName)) { //订单审核节点：设置反馈供应商的操作工号：订单表中supplierId对应供应商表中的operator（操作工号）
				operatorNo = engine.getWfmdao().getDbAccess().findById(BmePurchOrder.class,selectedTask.getServiceNo()).getBmeSupplier().getOperator();
			}
			else if("wf_cgdd_response".equals(taskName)) { //订单反馈节点：设置通知的操作工号：启动流程实例的人
				operatorNo = selectedTask.getServiceCreator();	
			}
		}
		else if(AppInitInfo.PROCESS_WF_FHD.equals(processName)){ //发货单流程		
			operatorNo = selectedTask.getServiceCreator();		
			//weixin_inform_userids = operatorNo+"|"+selectedTask.get.getServiceNo(),
			//weixin_inform_text;
		}
		else if(AppInitInfo.PROCESS_WF_YSDSH.equals(processName)){ //验收单流程		
			operatorNo = selectedTask.getServiceCreator();		
			//weixin_inform_userids = operatorNo+"|"+selectedTask.get.getServiceNo(),
			//weixin_inform_text;
		}
		else {
			operatorNo = "all";
		}

		args.put(AppInitInfo.APP_OPERATOR,operatorNo);	
		
		/*
		if("2".equals((String)args.get(AppInitInfo.APP_BUSINESS_TYPE))){  //订单,设置反馈供应商的操作工号：订单表中supplierId对应供应商表中的operator（操作工号）
			String supplierOperator = engine.getWfmdao().getDbAccess().findById(BmePurchOrder.class,selectedTask.getServiceNo()).getBmeSupplier().getOperator();
			args.put(AppInitInfo.APP_OPERATOR,supplierOperator);	
		}
		*/
		return args;
	}
	
	//处理行选择
   public void onTodoRowSelect(SelectEvent event) {
	    selectedTask = (WfmTask) event.getObject();	  
	    if(null!=selectedTask) {
		    //this.model = WfmDiagramModel.genProcessDiagramModel(selectedTask.getWfmProcess(),selectedTask.getTaskName()); //获取流程图模型
		    this.model = WfmDiagramModel.genProcessDiagramModel(selectedTask.getWfmProcess(),selectedTask.getTaskName()); //获取流程图模型
			//打开待处理页面
			uiTaskTodoPage = (null==selectedTask.getActionUrl() ? UI_TAST_TODO : selectedTask.getActionUrl() );
	    }
	    // 提取WfmNode数据字典
	    nodeList.clear();
		for(WfmNode po : selectedTask.getWfmProcess().getWfmNodes()) {
			nodeList.add(new SelectItem(po.getName(),po.getDisplayName()));
		}

   }
   //处理行选择
   public String viewInfoAction() {
	    if(null!=selectedTask) {
		    //this.model = WfmDiagramModel.genProcessDiagramModel(selectedTask.getWfmProcess(),selectedTask.getTaskName()); //获取流程图模型
		    this.model = WfmDiagramModel.genProcessDiagramModel(selectedTask.getWfmProcess(),selectedTask.getTaskName()); //获取流程图模型
			//打开待处理页面
			uiTaskTodoPage = ( (null==selectedTask.getActionUrl() || "".equals(selectedTask.getActionUrl())) ? "ui-task-todo" : selectedTask.getActionUrl() );
	    }
	    // 提取WfmNode数据字典
	    nodeList.clear();
		for(WfmNode po : selectedTask.getWfmProcess().getWfmNodes()) {
			nodeList.add(new SelectItem(po.getName(),po.getDisplayName()));
		}
		return null;
  }
   
    public void onTodoRowUnselect(UnselectEvent event) {
    }
    
    // handle File Upload
 	public void handleFileUpload(FileUploadEvent event) {
 		String fileId = IDHelper.genStrID(24);
 		uploadedFile = event.getFile().getFileName();//上传文件路径名
 		
 		String fileName = uploadedFile.substring(uploadedFile.lastIndexOf(AppInitInfo.WOS_SEPERATOR) + 1);

 		String fileExt = FileUtil.getFileExtension(new File(fileName));//上传文件路径名扩展名
 		String webfileName = AppInitInfo.WFM_UPLOAD_FILE_PATH + fileId +"." + fileExt;
 		log.info("webfileName: "+ webfileName);
 		
 		try {
 			FileUploadProcessor.saveInputStreamAsFile(event.getFile().getInputstream(),webfileName);
 			//文件存入数据库AppFileInfo
 			AppFileInfo afi = new AppFileInfo();
 			afi.setId(fileId);
 			afi.setForType("0");
 			afi.setForName(selectedTask.getTaskName());
 			afi.setForId(selectedTask.getId());
 			afi.setOperator(operator);
 			afi.setUpTime(new Date());
 			afi.setUpdName(uploadedFile);
 			afi.setFilePath(webfileName);
 			afi.setFileExt(fileExt);
 			//afi.setRemarks(remarks);
 			engine.getWfmdao().getDbAccess().begin();
 			engine.getWfmdao().getDbAccess().insert(afi);
 			engine.getWfmdao().getDbAccess().commit();
 			
 			log.info(uploadedFile + " is uploaded.");

 		} catch (IOException e) {
 			log.error(uploadedFile + " is uploaded failly.");
 		}
 		
 	}
 	
 	//show faces Messages
	public void showMessages(String summary,String detail) {	
		FacesMessage message = new FacesMessage(summary, detail);
		FacesContext.getCurrentInstance().addMessage(null, message);
	}

	public String getOperator() {
		return operator;
	}

	public void setOperator(String operator) {
		this.operator = operator;
	}

	public List<WfmTask> getVoList() {
		return voList;
	}

	public void setVoList(List<WfmTask> voList) {
		this.voList = voList;
	}

	public List<WfmTaskLog> getVoListLog() {
		return voListLog;
	}

	public void setVoListLog(List<WfmTaskLog> voListLog) {
		this.voListLog = voListLog;
	}

	public WfmTask getSelectedTask() {
		return selectedTask;
	}

	public void setSelectedTask(WfmTask selectedTask) {
		this.selectedTask = selectedTask;
	}

	public DefaultDiagramModel getModel() {
		return model;
	}

	public void setModel(DefaultDiagramModel model) {
		this.model = model;
	}

	public int getWorkResult() {
		return workResult;
	}

	public void setWorkResult(int workResult) {
		this.workResult = workResult;
	}

	public String getWorkRemarks() {
		return workRemarks;
	}

	public void setWorkRemarks(String workRemarks) {
		this.workRemarks = workRemarks;
	}

	public String getRollbackNode() {
		return rollbackNode;
	}

	public void setRollbackNode(String rollbackNode) {
		this.rollbackNode = rollbackNode;
	}

	public List<SelectItem> getNodeList() {
		return nodeList;
	}

	public void setNodeList(List<SelectItem> nodeList) {
		this.nodeList = nodeList;
	}
	public String getUploadedFile() {
		return uploadedFile;
	}

	public void setUploadedFile(String uploadedFile) {
		this.uploadedFile = uploadedFile;
	}

	public String getUiTaskTodoPage() {
		return uiTaskTodoPage;
	}

	public void setUiTaskTodoPage(String uiTaskTodoPage) {
		this.uiTaskTodoPage = uiTaskTodoPage;
	}

	public String getServiceNo() {
		return serviceNo;
	}

	public void setServiceNo(String serviceNo) {
		this.serviceNo = serviceNo;
	}
	
}
